using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Threading.Tasks;
using Comteck.Dto.Sys;
using Comteck.Entities.Sys;
using Comteck.Ktt.Services.Infrastructure;
using Dapper;
using ExpressMapper.Extensions;

namespace Comteck.Ktt.Services.Sys {
  /// <summary>
  /// 
  /// </summary>
  public class PrintTemplateService : BaseKttService, IPrintTemplateService {
    private readonly IKttRepository<PrintTemplate, string> _PrintTemplateRepository;
    private readonly IKttRepository<PrintTemplateData, string> _PrintTemplateDataRepository;

    public PrintTemplateService(IKttUnitOfWork unitOfWork) : base(unitOfWork) {
      _PrintTemplateRepository = _unitOfWork.GetRepository<PrintTemplate, string>();
      _PrintTemplateDataRepository = _unitOfWork.GetRepository<PrintTemplateData, string>();
    }
    /// <summary>
    /// 查询全部列表
    /// </summary>
    /// <returns></returns>
    public async Task<IEnumerable<PrintTemplateDto>> GetAllAsync() {
      var list = await _PrintTemplateRepository.GetAllAsync();
      return list.MapTo<IEnumerable<PrintTemplateDto>>();
    }

    /// <summary>
    /// 删除
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    public async Task<AjaxResponse> DeleteAsync(string id) {
      var result = new AjaxResponse() { Code = 0 };

      var main = await _PrintTemplateRepository.GetByIdAsync(id);
      var detailList = await _PrintTemplateDataRepository.FindAsync(x => x.TemplateId == id);

      if (main == null) {
        result.Message = "模版不存在";
        return result;
      }

      if (main.IsSystem == 1) {
        result.Message = "系统内置模版不允许删除";
        return result;
      }

      await _PrintTemplateRepository.RemoveAsync(main);
      await _PrintTemplateDataRepository.RemoveRangeAsync(detailList);

      result.Code = 1;
      return result;
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="templateId"></param>
    /// <returns></returns>
    public async Task<IEnumerable<PrintTemplateDataDto>> GetDetailListByTemplateIdAsync(string templateId) {
      var detailList = await _PrintTemplateDataRepository.FindAsync(x => x.TemplateId == templateId);
      return detailList.OrderBy(x => x.SeqNo).MapTo<List<PrintTemplateDataDto>>();
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    public async Task<PrintTemplateDto> GetEditModelAsync(string id) {
      PrintTemplateDto model;
      if (id.IsNullOrEmpty()) {
        model = new PrintTemplateDto() {
          Status = (int) EnumStatus.Valid,
          DataList = new List<PrintTemplateDataDto>()
        };
      } else {
        var entity = await _PrintTemplateRepository.GetByIdAsync(id);
        model = entity.MapTo<PrintTemplateDto>();
        model.DataList = (await this.GetDetailListByTemplateIdAsync(id)).ToList();
      }

      return model;
    }

    /// <summary>
    /// 保存
    /// </summary>
    /// <param name="model"></param>
    /// <returns></returns>
    public async Task<AjaxResponse<PrintTemplateDto>> SaveAsync(PrintTemplateDto model) {
      var result = new AjaxResponse<PrintTemplateDto>() {
        Code = 0
      };
      
      try {
        _unitOfWork.BeginTransaction();

        // check
        await this.CheckSaveAsync(model);

        // 移除起始字符前的多余字符
        model.Data = this.RemoveNeedlessWords(model.Data);

        var dbEntity = await _PrintTemplateRepository.GetByIdAsync(model.Id);

        if (dbEntity == null) {
          // add
          dbEntity = model.MapTo<PrintTemplate>();
          dbEntity.Id = Guid.NewGuid().ToString();

          var detailList = model.DataList.MapTo<List<PrintTemplateData>>();
          detailList.ForEach(x => {
            x.Id = Guid.NewGuid().ToString();
            x.TemplateId = dbEntity.Id;
          });

          await _PrintTemplateRepository.AddAsync(dbEntity);
          await _PrintTemplateDataRepository.AddRangeAsync(detailList);
        } else {
          // modify
          model.MapTo(dbEntity);
          var dbDetailList = await _PrintTemplateDataRepository.FindAsync(x => x.TemplateId == model.Id);
          await _PrintTemplateDataRepository.RemoveRangeAsync(dbDetailList);

          var detailList = model.DataList.MapTo<List<PrintTemplateData>>();
          detailList.ForEach(x => {
            x.Id = Guid.NewGuid().ToString();
            x.TemplateId = dbEntity.Id;
          });

          await _PrintTemplateRepository.UpdateAsync(dbEntity);
          await _PrintTemplateDataRepository.AddRangeAsync(detailList);
        }

        result.Code = 1;
        result.Data = dbEntity.MapTo<PrintTemplateDto>();

        await _unitOfWork.CommitTransactionAsync();
      } catch (Exception ex) {
        result.Message = ex.Message;
        _unitOfWork.RollbackTransaction();
      }

      return result;
    }

    /// <summary>
    /// 检查模板名称是否存在
    /// </summary>
    /// <param name="model"></param>
    private async Task CheckSaveAsync(PrintTemplateDto model) {
      if (await _PrintTemplateRepository.AnyAsync(x => x.Id != model.Id && x.Name == model.Name)) {
        throw new ComteckException("模板名称已经存在");
      }
    }

    /// <summary>
    /// 移除多余的字符(不可视字符，UTF-BOM三个EF BB BF字符，用无法Trim去除)
    /// </summary>
    private string RemoveNeedlessWords(string input) {
      var result = input;
      var startStr = "<?xml";
      var index = result.IndexOf(startStr);
      if (index == -1) {
        throw new ComteckException($"模板模式有误，未包含起始字符：{startStr}");
      }
      // 移除起始字符前的多余字符
      result = result.Remove(0, index);
      return result;
    }

    /// <summary>
    /// 获得打印数据源(支持单字段)
    /// </summary>
    /// <param name="model"></param>
    /// <returns></returns>
    public async Task<DataSet> GetPrintTemplatePrintDataSource(PrintTemplateQuery model) {
      var entity = await _PrintTemplateRepository.GetByIdAsync(model.Id);
      if (entity == null) {
        throw new ComteckException($"模版不存在");
      }

      // 获取关联脚本
      var dataList = await _PrintTemplateDataRepository.TableUntracked
        .Where(x => x.TemplateId == model.Id)
        .OrderBy(x => x.SeqNo)
        .ThenBy(x => x.Name)
        .ToListAsync();

      var ds = new DataSet();

      var conn = _PrintTemplateRepository.DbContext.Database.Connection;

      foreach (var dataModel in dataList) {
        // 加载数据
        var dataTable = new DataTable();
        dataTable.Load(await conn.ExecuteReaderAsync(dataModel.Sql, new { ids = model.PrintList }, null));
        dataTable.TableName = dataModel.Name;

        // 特殊处理：为主表添加自提点分组标记
        if (dataModel.Name == "table0" && dataTable.Columns.Contains("SelfOrgName")) {
          // 添加标记列
          if (!dataTable.Columns.Contains("IsFirstInSelfOrg")) {
            dataTable.Columns.Add("IsFirstInSelfOrg", typeof(int));
          }
          
          string previousSelfOrgName = string.Empty;
          foreach (DataRow row in dataTable.Rows) {
            string currentSelfOrgName = row["SelfOrgName"]?.ToString() ?? string.Empty;
            // 如果是新的自提点，标记为第一个
            if (currentSelfOrgName != previousSelfOrgName) {
              row["IsFirstInSelfOrg"] = 1;
              previousSelfOrgName = currentSelfOrgName;
            } else {
              row["IsFirstInSelfOrg"] = 0;
            }
          }
        }

        // 设置只读
        foreach (DataColumn column in dataTable.Columns) {
          column.ReadOnly = false;
        }

        ds.Tables.Add(dataTable);
      }

      return ds;
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="menuId"></param>
    /// <returns></returns>
    public async Task<List<PrintTemplateDto>> GetListByMenuIdAsync(string menuId, int? status) {
      var list = await _PrintTemplateRepository.TableUntracked
        .Where(x => x.MenuId == menuId)
        .WhereIIf(status != null, x => x.Status == status)
        .OrderBy(x => x.SeqNo)
        .ToListAsync();
      return list.MapTo<List<PrintTemplateDto>>();
    }

  }
}
